package com.iretailer.report.quartz.checkContractTime;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.iretailer.report.model.Companies;
import com.iretailer.report.model.Malls;
import com.iretailer.report.model.RenewalRecord;
import com.iretailer.report.model.enums.RenewalResult;
import com.iretailer.report.model.enums.RenewalType;
import com.iretailer.report.service.CompanyService;
import com.iretailer.report.service.MailService;
import com.iretailer.report.service.MallsService;
import com.iretailer.report.service.RenewalRecordService;
import com.iretailer.report.util.StringUtil;
import com.iretailer.report.util.TimeUtil;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Auther Bennie
 * @Date 2020/6/11 14:07
 * @Description
 */
@Component
@Slf4j
public class CheckContractTime {


    private final Configuration configuration;
    private final MallsService mallsService;
    private final CompanyService companyService;
    private final JavaMailSender mailSender;
    private final MailService mailService;
    private final RenewalRecordService renewalRecordService;

    @Value("${spring.mail.username}")
    private String sender;

    public CheckContractTime(Configuration configuration, CompanyService companyService, JavaMailSender mailSender, MallsService mallsService, MailService mailService, RenewalRecordService renewalRecordService) {
        this.configuration = configuration;
        this.companyService = companyService;
        this.mailSender = mailSender;
        this.mallsService = mallsService;
        this.mailService = mailService;
        this.renewalRecordService = renewalRecordService;
    }


    @Transactional
    public void execute() {
        log.info("Executing task -------------> checkContractTime");
        for (RenewalType renewalType : RenewalType.values()) {
            checkContractTime(renewalType);
        }
    }

    private void checkContractTime(RenewalType renewalType) {
        String subject = renewalType.equals(RenewalType.RENEWAL_NOTIFICATION) ?
                "契約満了日及び自動更新のお知らせ" :
                "契約自動更新完了のお知らせ";
        getMalls(renewalType).forEach((companies, malls) -> {
            String[] mails = companies.getPrincipalMail().split(",");
            try {
                mailService.send(mails, subject, new HashMap<String, Object>() {
                    {
                        put("datetime", LocalDateTime.now().format(TimeUtil.DEFAULT_DATE_TIME_FORMATTER));
                        put("renewalCompleted", false);
                        put("malls", malls.stream().map(mall -> {
                            LocalDate contractStartDate = (LocalDate) mall.get("contractStartDate");
                            LocalDate contractEndDate = (LocalDate) mall.get("contractEndDate");
                            return new HashMap<String, Object>() {
                                {
                                    put("store", mall.get("mallName"));
                                    put("startTime", dateFormat(contractStartDate));
                                    put("endTime", dateFormat(contractEndDate));
                                    put("terminateTime", dateFormat(contractEndDate.minusMonths(1)));
                                    put("renewalEndTime", dateFormat(contractEndDate.plusDays(1)));
                                }
                            };
                        }).collect(Collectors.toList()));
                    }
                }, "renewal-notification");
                List<RenewalRecord> renewalRecords = malls.stream().map(mall -> {
                    String mallId = (String) mall.get("mallId");
                    LocalDate contractStartDate = (LocalDate) mall.get("contractStartDate");
                    LocalDate contractEndDate = (LocalDate) mall.get("contractEndDate");
                    RenewalRecord renewalRecord = new RenewalRecord()
                            .setDatetime(LocalDateTime.now())
                            .setMallId(mallId)
                            .setRenewalType(renewalType.getName())
                            .setContractStartDate(contractStartDate)
                            .setContractEndDate(contractEndDate)
                            .setResult(RenewalResult.SUCCESS.getName());
                    if (renewalType.equals(RenewalType.RENEWAL_COMPLETION)) {
                        String newContractEndDate = dateFormat(contractEndDate.plusYears(1));
                        boolean update = mallsService.update(new Malls().setContractEndDate(newContractEndDate), new UpdateWrapper<Malls>().eq("Id" ,mallId));
                        if (update) {
                            renewalRecord.setDescription(String.format("自動更新前の契約有効期限: %s\t自動更新後の契約有効期限: %s",
                                    dateFormat(contractEndDate), newContractEndDate));
                        } else {
                            renewalRecord.setResult(RenewalResult.FAILURE.getName());
                            log.error("自动更新合同失败 【{} - {}】", companies.getName(), mall.get("mallName"));
                        }
                    }
                    return renewalRecord;
                }).collect(Collectors.toList());
                renewalRecordService.saveBatch(renewalRecords);
            } catch (MessagingException e) {
                log.error("发送邮件失败:", e);
            }
        });
    }


    private String dateFormat(LocalDate date) {
        return date.format(TimeUtil.DEFAULT_DATE_FORMATTER);
    }

    private Map<Companies, List<Map<String, Object>>> getMalls(RenewalType renewalType) {
        List<Map<String, Object>> malls = Collections.emptyList();
        switch (renewalType) {
            case RENEWAL_COMPLETION:
                malls = renewalRecordService.getRenewalCompletedMalls();
                break;
            case RENEWAL_NOTIFICATION:
                malls = renewalRecordService.getAutomaticRenewalMalls();
                break;
            default:
                break;
        }

        if (malls.isEmpty()) {
            log.warn("未获取到 【{}】 的 案场", renewalType.getName());
            return Collections.emptyMap();
        }
        return malls.stream().filter(mall -> {
            String email = (String) mall.get("mail");
            LocalDate contractStartDate = (LocalDate) mall.get("contractStartDate");
            LocalDate contractEndDate = (LocalDate) mall.get("contractEndDate");
            if (StringUtils.isBlank(email)) {
                log.warn("【{}】公司未提供联系邮箱，将无法提供自动续合同服务。", mall.get("companyName"));
                return false;
            }
            if (contractStartDate == null || contractEndDate == null) {
                log.warn("【{}】公司未正确设置合同有效期，将无法提供自动续合同服务。", mall.get("companyName"));
                return false;
            }
            String mallId = (String) mall.get("mallId");
            int count = renewalRecordService.count(new QueryWrapper<RenewalRecord>().lambda()
                    .eq(RenewalRecord::getContractStartDate, contractStartDate)
                    .eq(RenewalRecord::getContractEndDate, contractEndDate)
                    .eq(RenewalRecord::getMallId, mallId)
                    .eq(RenewalRecord::getResult, RenewalResult.SUCCESS)
                    .eq(RenewalRecord::getRenewalType, renewalType));
            return count == 0;
        }).collect(Collectors.groupingBy(mall -> new Companies().setId((String) mall.get("companyId"))
                .setName((String) mall.get("companyName")).setPrincipalMail((String) mall.get("mail"))));
    }


    @Transactional
    @Deprecated
    public void executeDeprecated() {


        List<Malls> mallsList = mallsService.list(new QueryWrapper<Malls>().lambda().eq(Malls::getEnabled, 1).orderByAsc(Malls::getCompanyId));
        if (mallsList.isEmpty()) return;


        // 当前时间减去两个月
        LocalDate judgmentDay = LocalDate.now().plusMonths(-2);
        List<Malls> sendMailMalls = new ArrayList<>();
        // 需要自动续费的商铺列表

        List<Malls> autoRenewalList = mallsList.stream().filter(mall -> {
            // 合同结束时间
            String contractEndDate = mall.getContractEndDate();
            if (StringUtils.isBlank(contractEndDate)) return false;
            return TimeUtil.parse_LocalDate(contractEndDate).isBefore(judgmentDay);
        }).collect(Collectors.toList());


        mallsList.forEach(m -> {
            String contractEndDate = m.getContractEndDate();
            if (StringUtils.isNotBlank(contractEndDate)) {
                try {
                    LocalDate endDate = TimeUtil.parse_LocalDate(contractEndDate);
                    if (!endDate.isAfter(judgmentDay)) {
                        sendMailMalls.add(m);
                    }
                } catch (Exception e) {
                    log.error("日期'{}'格式错误转换失败", contractEndDate, e);
                }
            }
        });

        sendMailMalls.stream().collect(Collectors.groupingBy(Malls::getCompanyId)).forEach((key, value) -> {
            Companies companies = companyService.getById(key);
            if (companies != null && StringUtil.notEmpty(companies.getPrincipalMail())) {
                String[] mails = companies.getPrincipalMail().split(",");
                List<Map<String, Object>> mapList = new ArrayList<>();
                for (Malls mall : value) {
                    Map<String, Object> map = new HashMap<>();
                    map.put("name", mall.getName());
                    map.put("startDate", mall.getContractStartDate());
                    map.put("endDate", mall.getContractEndDate());
                    LocalDate date = TimeUtil.parse_LocalDate(mall.getContractEndDate()).plusYears(1);
                    String dateStr = TimeUtil.localDate_format(date);
                    map.put("date", dateStr);
                    mall.setContractEndDate(dateStr);
                    mapList.add(map);
                }
                boolean sendMail = sendMail(mails, mapList, mailSender);
                if (sendMail) {
                    mallsService.updateBatchById(value);
                }
            }
        });

        log.info("---- end check contract time ----");
    }


    private boolean sendMail(String[] mails, List<Map<String, Object>> items, JavaMailSender mailSender) {
        Map<String, Object> context = new HashMap<>();
        context.put("items", items);
        try {
            MimeMessage mailMessage = mailSender.createMimeMessage();
            Template template = configuration.getTemplate("pdf/checkContractTime.ftl");
            String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, context);

            MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mailMessage, true);
            mimeMessageHelper.setFrom(sender);
            mimeMessageHelper.setTo(mails);
            mimeMessageHelper.setSubject("契約自動更新完了のお知らせ");
            mimeMessageHelper.setText(html, true);
            mailSender.send(mailMessage);
            return true;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return false;
        }
    }


}
